import * as THREE from "../../../modules/three/three.module.js";
import ModelEntity from "./ModelEntity.js";
import BulletEntity from "./BulletEntity.js";
import {d2r, MouseButton} from "../lib/CommonConsts.js";
import SphericalUpZ from "../util/SphericalUpZ.js";
import {OBB} from "../../../modules/three/jsm/math/OBB.js";

const offset = new THREE.Vector3(0, 5, 2)
const unitY = new THREE.Vector3(0, 1, 0)
const unitZ = new THREE.Vector3(0, 0, 1)

const _obb4Drone = new OBB()
const _mat = new THREE.Matrix4()
const rotateStart = new THREE.Vector2()
const rotateEnd = new THREE.Vector2()
const rotateDelta = new THREE.Vector2();
const rotateSpeed = 1
const sphericalDelta = new SphericalUpZ();
const spherical = new SphericalUpZ();
const posDiff = new THREE.Vector3()
const front = new THREE.Vector3()
let downing = false
const scope = {
  minPolarAngle: 0,
  maxPolarAngle: 90 * d2r
}
function rotateLeft( angle ) {
  sphericalDelta.theta += angle;
}

function rotateUp( angle ) {
  sphericalDelta.phi -= angle;
}

export default class AircraftEntity extends ModelEntity {
  /**
   * @type {THREE.AnimationMixer}
   */
  mixer
  dir = new THREE.Vector3()
  bullets = []
  // 当movingByCollision不为空时，不能移动和旋转无人机
  movingByCollision = []

  constructor(vo, glbMap, modelLoaded) {
    super(vo, glbMap, modelLoaded);
    this.dir.set()
  }

  onGltfLoadFinish(gltfScene, gltf) {
    super.onGltfLoadFinish(gltfScene, gltf);
    const mixer = new THREE.AnimationMixer(gltfScene);
    gltf.animations.forEach(clip => {
      const action = mixer.clipAction(clip);
      action.play();
    })
    this.mixer = mixer
    this.clock = new THREE.Clock()
    this.dir.set(0, 1, 0).applyEuler(this.vo.rotation)
  }

  tick(clock, keyboard, camera) {
    if (this.movingByCollision.length) {
      const velocity = this.movingByCollision.shift()
      const dz = camera.position.z - this.position.z
      this.position.add(velocity)
      if (this.position.z < 3) {
        this.position.z = 3
      }
      camera.position.add(velocity)
      camera.position.z = this.position.z + dz
      return;
    }
    const delta = clock.getDelta();
    let moveDistance = 5 * delta;
    const rotateAngle = (Math.PI / 2) * delta;
    posDiff.copy(this.position)
    if (keyboard.modifiers['shift']) {
      moveDistance *= 10
    }
    if (keyboard.pressed("s")) {
      this.translateY(moveDistance);
    }
    if (keyboard.pressed("w")){
      this.translateY(-moveDistance);
    }
    if (keyboard.pressed("a")) {
      this.translateX(moveDistance);
    }
    if (keyboard.pressed("d")) {
      this.translateX(-moveDistance);
    }

    if (keyboard.pressed("q")) {
      this.translateZ(moveDistance);
    }
    if (keyboard.pressed("e") && this.position.z >= 3) {
      this.translateZ(-moveDistance);
    }
    posDiff.sub(this.position).negate()
    camera.position.add(posDiff)
    if (keyboard.pressed("r")) {
      this.rotateOnAxis(new THREE.Vector3(0, 0, 1), rotateAngle)
      this.updateCameraByTurning(camera)
    }
    if (keyboard.pressed("f")) {
      this.rotateOnAxis(new THREE.Vector3(0, 0, 1), -rotateAngle)
      this.updateCameraByTurning(camera)
    }
  }

  updateCameraByTurning(camera) {
    this.dir.set(0, -1, 0).applyQuaternion(this.quaternion)
    offset.copy(this.dir).negate()
    spherical.setFromVector3( offset )
    const theta = spherical.theta
    offset.copy( camera.position ).sub( this.position )
    spherical.setFromVector3( offset )
    spherical.theta = theta
    spherical.toVector3(offset)
    camera.position.copy(this.position).add(offset)
    camera.lookAt(this.position)
  }

  collided(force) {
    const arr = this.movingByCollision
    arr.length = 0
    for (let i = 35; i >= 1; i--) {
      const a = Math.sqrt(i)
      arr.push(force.clone().multiplyScalar(a))
    }
  }

  fire() {
    const bulletPos = new THREE.Vector3().copy(this.position).addScaledVector(this.dir, 1)
    const bullet = new BulletEntity(bulletPos,this.dir);
    this.bullets.push(bullet);
    this.parent.add(bullet);
    bullet.uav = this;
  }

  tickFire() {
    this.bullets.forEach(it => it.tick());
  }
  getObb() {
    _obb4Drone.fromBox3(this.boundingBox)
    _obb4Drone.center.copy(this.position)
    _mat.makeRotationFromQuaternion(this.quaternion)
    _obb4Drone.rotation.setFromMatrix4(_mat)
    return _obb4Drone
  }

  pointerDown(event, camera){
    if (this.movingByCollision.length) {
      return;
    }
    if (event.button === MouseButton.left) {
      downing = true
      rotateStart.set( event.clientX, event.clientY );
      // offset.copy( camera.position ).sub( this.position );
      // spherical.setFromVector3( offset );
      // console.log(spherical.phi, spherical.theta)
      return
    }

  }
  pointerMove(event, camera){
    if (this.movingByCollision.length) {
      return;
    }
    if (!downing) {
      return
    }
    rotateEnd.set( event.clientX, event.clientY );
    rotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( rotateSpeed );
    rotateLeft( 2 * Math.PI * rotateDelta.x / innerHeight ); // yes, height
    rotateUp( 2 * Math.PI * rotateDelta.y / innerHeight );
    rotateStart.copy( rotateEnd );
    offset.copy( camera.position ).sub( this.position );

    spherical.setFromVector3( offset );
    spherical.theta += sphericalDelta.theta;
    // console.log(sphericalDelta.theta)
    spherical.phi += sphericalDelta.phi;
    spherical.phi = Math.max( scope.minPolarAngle, Math.min( scope.maxPolarAngle, spherical.phi ) )
    // spherical.theta = Math.max( scope.minPolarAngle, Math.min( scope.maxPolarAngle, spherical.phi ) )
    spherical.makeSafe()
    // console.log(spherical.phi, spherical.theta)
    spherical.toVector3(offset)

    camera.position.copy(this.position).add(offset)
    camera.lookAt(this.position)
    sphericalDelta.set( 0, 0, 0 );
    front.set(0, 0, 1).applyQuaternion(camera.quaternion)
    front.z = 0
    front.normalize()
    this.quaternion.setFromUnitVectors(unitY, front)
    this.dir.set(0, -1, 0).applyQuaternion(this.quaternion)
  }
  pointerUp(event, camera){
    downing = false
    // offset.copy( camera.position ).sub( this.position );
    // spherical.setFromVector3( offset );
    // console.log(spherical.phi, spherical.theta)
  }
}
